<?php
	/**
	 * <version greek="beta" major="1" minor="0">Cochin Splash Hen</version>
	 * <author email="njones@art-k-tec.com">Nika Jones</author>
	 * <copyright start="2007">Art-k-tec Systems, LLC</copyright>
	 * <license type="Apache2.0" href="http://www.opensource.org/licenses/apache2.0.php">Apache License, Version 2.0</license>
	 *
	 * <summary>
	 *    This provides a consistant interface for data interaction whether it
	 *    is from a file, database or XML source. It provides a object-like
	 *    interaction with the data.
	 * <summary>
	 */
	 /**
	  * <summary>
	  *    Provides the interface that all bLinq Datastores need
	  *    to implement for a consistant interaction with the data.
	  * </summary>
	  */
	$sDataStorePath =dirname(__FILE__).'/bLinq/';
	
	include($sDataStorePath.'bLinqStore.class.inc');
	include($sDataStorePath.'bLinqFile.class.inc');
	include($sDataStorePath.'bLinqMock.class.inc');
	include($sDataStorePath.'bLinqSql.class.inc');
	
	class bLinq extends ArrayObject {
		
		const CASE_INSENSITIVE ='ci';
		const NUMERIC ='no';
		
		protected $aQuery;
		protected $aKeyValue;
		protected $aMergeKey;
		protected $aMergeKeyFormat;
		protected $oDataStore;
		
		private $_OR_STATE =false;
		private $_AND_STATE =false;
		private $_WHERE_STATE =false;
		
		public function __construct($oData) {
			
			$this->aMergeKey =array();
			$this->aMergeKeyFormat =array();
			$this->oDataStore =$oData;
		}
		
		public function RawQuery() {
			
			return $this->aQuery;
		}
		
		public function RawKeyValue() {
			
			return $this->aKeyValue;
		}
		
		public function MergeKeys() {
			
			return array(
				'keys' =>$this->aMergeKey,
				'format' =>$this->aMergeKeyFormat
			);
		}
		
		public function From($sDataSource) {
			
			$this->aQuery['from'] =strtolower($sDataSource);
			return $this;
		}

		public function In($sDataSource) {
			
			$this->aQuery['in'] =$sDataSource;
			return $this;
		}
		
		public function Page($nPage, $nNumberPerPage =10) {
			
			$this->aQuery['page'] =array($nPage, $nNumberPerPage);
			return $this;
		}
		
		public function __call($sKey, $aParameters) {
			
			if(isset($this->_ORDERBY_STATE)) {
				
				$this->aQuery['orderby'][$sKey] =(string)$aParameters[0];
				unset($this->_ORDERBY_STATE);
				
				return $this;
			}
			
			if(method_exists($this->oDataStore, $sKey)) {
				
				array_unshift($aParameters, $this); // puts the $this as the first parameter.
				
				return  call_user_func_array(array($this->oDataStore, $sKey), $aParameters);
			}
			
			return $this;
		}

		public function __get($sKey) {
		
			$this->sGetKey =$sKey;
			if(isset($this->_ORDERBY_STATE)) {
				
				unset($this->_ORDERBY_STATE);
			}
			
			switch(strtolower($sKey)) {
				
				case "orderby":
					$this->_ORDERBY_STATE =true;
				break;
			}
			
			if($this->_WHERE_STATE) {
				
				if(strtolower($sKey) =='or') {
					
					$this->_OR_STATE =true;
					return $this;
				}
				
				if(strtolower($sKey)  =='and') {
					
					return $this;
				}
				
				if($this->_OR_STATE ==true) {
				
					$this->aQuery['where'][$sKey]['or'] =array();
				} else {
					
					$this->aQuery['where'][$sKey] =array();
				}
				
				return $this;
			}
			
			switch(strtolower($sKey)) {
			
				case "where":
					$this->_WHERE_STATE =true;
				break;
				case "and":
					$this->_WHERE_STATE =true;
					$this->_AND_STATE =true;
				break;
				case "or":
					$this->_WHERE_STATE =true;
					$this->_OR_STATE =true;
				break;
				default:
			}
			
			return $this;
		}
		
		public function offsetGet($sValue) {
			
			if(isset($this->_ORDERBY_STATE)) {
				
				unset($this->_ORDERBY_STATE);
			}
			
			if($this->sGetKey !=null) {
				
				switch(strtolower($this->sGetKey)) {
				
					case "where":
						$this->_WHERE_STATE =false;
					break;
					case "and":
						$this->_WHERE_STATE =false;
						$this->_AND_STATE =false;
					break;
					case "or":
						$this->_WHERE_STATE =false;
						$this->_OR_STATE =false;
					break;
				}
				
				if($sValue instanceof bLinqMerge) {
				
					$sFormat =$sValue->Format();
					if(isset($sFormat)) {
						
						$this->aMergeKeyFormat[$this->sGetKey] =$sFormat;
					}
					
					$sValue =$sValue->Value();
					$this->aMergeKey[] = $this->sGetKey;
				}
				
				$this->aKeyValue[strtolower($this->sGetKey)] =$sValue; 
			}
			
			return $this;
		}
		
		public static function Overwrite($sText, $sFormat =null) {
			
			return new bLinqMerge($sText, $sFormat);
		}
	}
	
	class bLinqRow extends ArrayObject { public function __toString() { return (string)$this[0]; } }
	
	class bLinqMerge { 
		
		private $mValue;
		private $sFormat;
		
		public function __construct($mValue, $sFormat =null) { 
			
			$this->mValue =$mValue;
			$this->sFormat =$sFormat;
		} 

		public function Value() { 
		
			return $this->mValue;
		}
		
		public function Format() { 
		
			return $this->sFormat;
		}
	}
	
	class bLinqResult extends ArrayObject implements Iterator {
	
		private $nPosition =0;
		private $aInternalData;
		
		public function __construct() {
			
			$this->aInternalData =array();
		}
		
		public function Count() {
			
			if($this->aInternalData ==null || count($this->aInternalData) ==0) {
				
				return 0;
			}
			return count((array)$this->aInternalData[key($this->aInternalData)]);
		}
		
		public function key() {
			
			$this->nPosition;
		}
			
		public function current() {
		
			$oRow = new bLinqRow();
			foreach($this->aInternalData as $sField=>$aValues) {
				
				$oRow[$sField] =$aValues[$this->nPosition];
			}
			
			return $oRow;
		}
		
		public function next() {
			
			$this->nPosition++;
		}
		
		public function rewind() {
			
			return $this->nPosition =0;
		}
		
		public function valid() {
			
			
			$aFields =end($this->aInternalData);
			return isset($aFields[$this->nPosition]);
		}
		
		public function Add($aData) {
			
			foreach($aData as $sKey => $sValue) {
				
				$sKey =strtolower($sKey);
				if(!isset($this->aInternalData[$sKey])) {
					
					$this->aInternalData[$sKey] =new bLinqRow();
				}
				
				$this->aInternalData[$sKey][] =$sValue;
			}	
		}
		
		public function __get($sKey) {
			
			if(isset($this->aInternalData[strtolower($sKey)])) {
				
				return $this->aInternalData[strtolower($sKey)];
			} else {
				
				return null;
			}
		}
		
		public function __isset($sKey) {
			
			return isset($this->aInternalData[strtolower($sKey)]);
		}
		
		public function AsArray() {
			
			return $this->aInternalData;
		}
	}
?>